/**
* @Title: HttpRequestHandler.java
* @Package com.an.websocket
* @Description: TODO(用一句话描述该文件做什么)
* @author antch,861710865@qq.com
* @date 2017年7月21日 上午11:07:41
* @version V1.0
*/

package com.an.websocket;

import java.io.File;
import java.io.RandomAccessFile;
import java.net.URISyntaxException;
import java.net.URL;

import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.DefaultFileRegion;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.DefaultHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaderValues;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpUtil;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.LastHttpContent;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.stream.ChunkedNioFile;

/**
 * @ClassName: HttpRequestHandler
 * @Description: TODO(此类用来处理FullHttpRequest信息)
 * @author antch,861710865@qq.com
 * @date 2017年7月21日 上午11:07:41
 *
 */

public class HttpRequestHandler extends SimpleChannelInboundHandler<FullHttpRequest> {

	private final String wsUri;

	private static final File INDEX;

	static {
		URL location = HttpRequestHandler.class.getProtectionDomain().getCodeSource().getLocation();
		String path;
		try {
			path = location.toURI() + "WebsocketChatClient.html";
			path = !path.contains("file:") ? path : path.substring(5);
			INDEX = new File(path);
		} catch (URISyntaxException e) {
			// TODO Auto-generated catch block
			throw new IllegalStateException("Unable to locate WebsocketChatClient.html", e);
		}

	}

	public HttpRequestHandler(String wsUri) {
		super();
		this.wsUri = wsUri;
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		Channel channel = ctx.channel();
		System.out.println("Client:" + channel.remoteAddress() + "异常");
		// 出现异常打印异常信息并关闭连接
		cause.printStackTrace();
		ctx.close();
	}

	@Override
	protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
		if (wsUri.equalsIgnoreCase(request.uri())) {
			// 如果请求的是websocket升级，递增引用计数器，并且将它传递给在
			// ChannelPipeline 中的下个 ChannelInboundHandler
			ctx.fireChannelRead(request.retain());
		} else {
			if (HttpUtil.is100ContinueExpected(request)) {
				//处理符合 HTTP 1.1的 "100 Continue" 请求
				send100Continue(ctx);
			}

			//读取默认的 WebsocketChatClient.html 页面
			RandomAccessFile randomAccessFile = new RandomAccessFile(INDEX, "r");

			HttpResponse response = new DefaultHttpResponse(request.protocolVersion(), HttpResponseStatus.OK);
			response.headers().set(HttpHeaderNames.CONTENT_TYPE.toString(), "text/html;charset=UTF-8");

			boolean keepAlive = HttpUtil.isKeepAlive(request);

			//判断 keepalive 是否在请求头里面
			if (keepAlive) {
				response.headers().set(HttpHeaderNames.CONTENT_LENGTH.toString(), randomAccessFile.length());
				response.headers().set(HttpHeaderNames.CONNECTION.toString(), HttpHeaderValues.KEEP_ALIVE);

			}

			//写 HttpResponse 到客户端
			ctx.write(response);

			/*
			 * 写 index.html 到客户端，判断 SslHandler 是否在 ChannelPipeline
			 * 来决定是使用 DefaultFileRegion 还是 ChunkedNioFile
			 */
			if (ctx.pipeline().get(SslHandler.class) == null) {
				ctx.write(new DefaultFileRegion(randomAccessFile.getChannel(), 0, randomAccessFile.length()));
			} else {
				ctx.write(new ChunkedNioFile(randomAccessFile.getChannel()));
			}

			//写并刷新 LastHttpContent 到客户端，标记响应完成
			ChannelFuture future = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
			if (!keepAlive) {
				//如果 keepalive 没有要求，当写完成时，关闭 ChannelHttpRequestHandler
				future.addListener(ChannelFutureListener.CLOSE);
			}
			randomAccessFile.close();
		}
	}

	private void send100Continue(ChannelHandlerContext ctx) {
		FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE);
		ctx.writeAndFlush(response);
	}
}